package com.cz.mydao.pool;

import com.cz.mydao.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 功能描述: 自定义数据库连接池
 *
 * @author: 程长
 * @date: 2024/12/28 22:07
 * @version: 1.0
 */
@Slf4j
public class CustomConnectionPool {
    /**
     * 数据库连接驱动
     */
    private final String driver;

    /**
     * url路径
     */
    private final String url;

    /**
     * 用户名
     */
    private final String username;

    /**
     * 密码
     */
    private final String password;

    /**
     * 初始化连接数
     */
    @Value("${spring.datasource.pool.initial-size}")
    private int initialSize;

    /**
     * 最小空闲连接数
     */
    @Value("${spring.datasource.pool.min-idle}")
    private int minIdle;

    /**
     * 最大活跃连接数
     */
    @Value("${spring.datasource.pool.max-active}")
    private int maxActive;

    /**
     * 获取连接的最大等待时间（单位：毫秒）
     */
    @Value("${spring.datasource.pool.max-wait}")
    private int maxWait;

    /**
     * 连接池中保存的连接
     */
    private final Queue<Connection> idleConnections = new LinkedList<>();

    /**
     * 连接池中当前的连接数
     */
    private int currentSize = 0;

    public CustomConnectionPool(String driver, String url, String username, String password) {
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
        initializePool();

    }


    /**
     * 初始化连接池
     */
    private void initializePool() {
        try {
            // 加载数据库驱动
            Class.forName(driver);

            // 创建初始连接
            for (int i = 0; i < initialSize; i++) {
                idleConnections.offer(createNewConnection());
                currentSize++;
            }
            log.info("数据库连接池初始化完成，初始连接数: {}", initialSize);
        } catch (Exception e) {
            throw new RuntimeException(Constant.DB_INIT_FAIL, e);
        }
    }

    /**
     * 创建新连接
     *
     * @return 连接
     */
    private Connection createNewConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    /**
     * 获取连接
     *
     * @return 数据库连接
     */
    public Connection getConnection() throws InterruptedException, SQLException {
        long startTime = System.currentTimeMillis();

        synchronized (idleConnections) {
            // 当线程池中没有空闲连接 且 当前连接数超出最大连接数 只有等待归还连接
            while (idleConnections.isEmpty() && currentSize >= maxActive) {

                long waitTime = System.currentTimeMillis() - startTime;
                if (waitTime >= maxWait) {
                    throw new SQLException(Constant.DB_CONNECTION_TIMEOUT);
                }
                // 让该线程等待
                idleConnections.wait(maxWait - waitTime);
            }

            if (idleConnections.isEmpty()) {
                // 如果连接池为空，创建新的连接
                idleConnections.offer(createNewConnection());
                currentSize++;
            }

            // 获取一个连接并移除队列
            return idleConnections.poll();
        }
    }

    /**
     * 归还连接
     *
     * @param connection 要归还的连接
     */
    public void returnConnection(Connection connection) {
        if (connection != null) {
            synchronized (idleConnections) {
                // 先校验连接是否有效
                if (validateConnection(connection)) {
                    // 如果连接池中连接数小于最小空闲数，则直接归还
                    if (idleConnections.size() < minIdle) {
                        idleConnections.offer(connection);
                    } else {
                        try {
                            // 如果达到最小空闲连接数，不再保留这个连接
                            connection.close();
                            currentSize--;
                        } catch (SQLException e) {
                            log.error("关闭连接失败", e);
                        }
                    }
                } else {
                    try {
                        // 如果连接无效，则直接关闭
                        connection.close();
                    } catch (SQLException e) {
                        log.error("关闭无效连接失败", e);
                    }
                }
                // 唤醒在等待的线程
                idleConnections.notify();
            }
        }
    }

    /**
     * 校验连接是否有效
     *
     * @param connection 连接
     * @return 是否有效
     */
    public boolean validateConnection(Connection connection) {
        try {
            // 校验连接有效性
            return connection != null && connection.isValid(2);
        } catch (SQLException e) {
            log.error("连接无效", e);
            return false;
        }
    }

    /**
     * 关闭连接池中的所有连接
     */
    public void closePool() {
        synchronized (idleConnections) {
            for (Connection connection : idleConnections) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    log.error("关闭连接池中的连接失败", e);
                }
            }
            idleConnections.clear();
            currentSize = 0;
            log.info("连接池已关闭");
        }
    }
}
